package com.baidu.elinkagescroll;

import com.baidu.elinkagescroll.utils.LogUtil;

import ohos.agp.utils.Point;

import ohos.multimodalinput.event.TouchEvent;

/**
 * Helper for tracking the position of touch events.
 *
 * User should use this class to obtain finger touch position, and
 * position of Layout Container{@link }
 *
 * @since 2021/07/16.
 */
public class PosIndicator {
    // 手指滑动方向
    private static int SCROLL_ORIENTATION_NONE = -1;
    // 手指滑动方向 -- 垂直
    private static int SCROLL_ORIENTATION_VERTICAL = 0;
    // 手指滑动方向 -- 水平
    private static int SCROLL_ORIENTATION_HORIZONTAL = 1;

    // debug 开关.
    private boolean DEBUG = false;
    // 初始位置，在的onSizeChanged()中确定
    private int mStartPos = 0;
    // 结束位置，在的onSizeChanged()中确定
    private int mEndPos = 0;
    // 手指移动坐标
    private Point mLastMovePoint = new Point();
    // 手指按下坐标
    private Point mDownPoint = new Point();
    // 手指释放坐标
    private Point mReleasePoint = new Point();
    // 联动容器中，子view的当前位置: [mStartPos, mEndPos]
    private int mCurrentPos;
    // 联动容器中，子view的上次位置: [mStartPos, mEndPos]
    private int mLastPos;
    // 手指按下时，联动容器中，子view的位置: [mStartPos, mEndPos]
    private int mPressedPos;
    // 手指move的offset
    private double mOffsetX;
    // 手指move的offset
    private double mOffsetY;
    // 手指move后离按下点的distance
    private double mDistanceToDownX;
    // 手指move后离按下点的distance
    private double mDistanceToDownY;
    // 是否处于touch中
    private boolean mIsUnderTouch;
    // flag：横竖屏切换
    private boolean mConfigurationHasChanged;
    // 当前mCurrentPos在mStartPos和mEndPos之间的比例值
    private double mSaveCurrentPosRatio;
    // MotionEvent.XXX_ACTION
    private int mTouchAction = -1;
    // touch slop
    private int mTouchSlop;
    // 是否处于拖拽状态
    private boolean mIsDragging;
    // 手指滑动方向
    private int mScrollOrientation = SCROLL_ORIENTATION_NONE;

    public PosIndicator(boolean DEBUG) {
        this.DEBUG = DEBUG;
    }

    /**
     * 初始化Layout Container 位置信息
     *
     * @param startPos startPos
     * @param endPos endPos
     */
    public void initStartAndEndPos(int startPos, int endPos) {
        mStartPos = startPos;
        mEndPos = endPos;
    }


    /**
     * 跟踪手指坐标： 按下
     *
     * @param positionX positionX
     * @param positionY positionY
     */
    public void onDown(float positionX, float positionY) {
        mIsUnderTouch = true;
        mPressedPos = mCurrentPos;
        mLastMovePoint.modify(positionX, positionY);
        mDownPoint.modify(positionX, positionY);
        mTouchAction = TouchEvent.PRIMARY_POINT_DOWN;
    }

    /**
     * 跟踪手指坐标： 移动
     *
     * @param positionX positionX
     * @param positionY positionY
     */
    public void onMove(double positionX, double positionY) {
        double offsetX = positionX - mLastMovePoint.getPointX();
        double offsetY = positionY - mLastMovePoint.getPointY();
        if (!mIsDragging && Math.abs(offsetY) > mTouchSlop) {
            mIsDragging = true;
            if (offsetY < 0) {
                offsetY += mTouchSlop;
            } else {
                offsetY -= mTouchSlop;
            }
            mScrollOrientation = SCROLL_ORIENTATION_VERTICAL;
        }
        if (!mIsDragging && Math.abs(offsetX) > mTouchSlop) {
            mIsDragging = true;
            if (offsetX < 0) {
                offsetX += mTouchSlop;
            } else {
                offsetX -= mTouchSlop;
            }
            mScrollOrientation = SCROLL_ORIENTATION_HORIZONTAL;
        }
        if (mIsDragging) {
            setOffset(offsetX, offsetY);
            setDistanceToDown(positionX, positionY);
            mLastMovePoint.modify((float)positionX, (float)positionY);
            mTouchAction = TouchEvent.POINT_MOVE;
        }
    }

    /**
     * 是否是垂直滑动
     *
     * @return isScrollVertical
     */
    public boolean isScrollVertical() {
        return mScrollOrientation == SCROLL_ORIENTATION_VERTICAL;
    }

    /**
     * 是否是水平滑动
     *
     * @return isScrollHorizontal
     */
    public boolean isScrollHorizontal() {
        return mScrollOrientation == SCROLL_ORIENTATION_HORIZONTAL;
    }

    /**
     * 手指上滑
     *
     * @return isMoveUp
     */
    public boolean isMoveUp() {
        return getOffsetY() < 0;
    }

    /**
     * 手指下滑
     *
     * @return isMoveDown
     */
    public boolean isMoveDown() {
        return getOffsetY() > 0;
    }

    /**
     * 是否处于dragging状态
     *
     * @return isDragging
     */
    public boolean isDragging() {
        return mIsDragging;
    }

    /**
     * 跟踪手指坐标： 抬起
     *
     * @param positionX positionX
     * @param positionY positionY
     */
    public void onRelease(float positionX, float positionY) {
        mIsUnderTouch = false;
        mIsDragging = false;
        mReleasePoint.modify(positionX, positionY);
        mTouchAction = TouchEvent.PRIMARY_POINT_UP;
        mScrollOrientation = SCROLL_ORIENTATION_NONE;
    }

    /**
     * onPointerDown
     *
     * @param positionX positionX
     * @param positionY positionY
     */
    public void onPointerDown(float positionX, float positionY) {
        mLastMovePoint.modify(positionX, positionY);
    }

    /**
     * onPointerUp
     *
     * @param positionX positionX
     * @param positionY positionY
     */
    public void onPointerUp(float positionX, float positionY) {
        mLastMovePoint.modify(positionX, positionY);
    }

    /**
     * 获取手指按下点坐标
     *
     * @return FingerDownPoint
     */
    public Point getFingerDownPoint() {
        return mDownPoint;
    }

    /**
     * 获取手指move坐标
     *
     * @return FingerMovePoint
     */
    public Point getFingerMovePoint() {
        return mLastMovePoint;
    }

    /**
     * 获取手指抬起坐标
     *
     * @return FingerReleasePoint
     */
    public Point getFingerReleasePoint() {
        return mReleasePoint;
    }

    /**
     * 获取TouchAction
     *
     * @return {MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE, MotionEvent.ACTION_UP}
     */
    public int getTouchAction() {
        return mTouchAction;
    }

    /**
     * 设置touch slop
     *
     * @param touchSlop touchSlop
     */
    public void setTouchSlop(int touchSlop) {
        this.mTouchSlop = touchSlop;
    }

    /**
     * 获取touch slop
     *
     * @return TouchSlop
     */
    public int getTouchSlop() {
        return mTouchSlop;
    }

    private void setDistanceToDown(double positionX, double positionY) {
        mDistanceToDownX = positionX - mDownPoint.getPointX();
        mDistanceToDownY = positionY - mDownPoint.getPointY();
    }

    /**
     * 手指是否touch中
     *
     * @return UnderTouch
     */
    public boolean isUnderTouch() {
        return mIsUnderTouch;
    }

    /**
     * 按下后，联动容器{@link }的位置是否发生了改变
     *
     * @return hasMovedAfterPressedDown
     */
    public boolean hasMovedAfterPressedDown() {
        return mCurrentPos != mPressedPos;
    }

    private void setOffset(double positionX, double positionY) {
        mOffsetX = positionX;
        mOffsetY = positionY;
    }

    /**
     * 手指Move的偏移量
     *
     * @return OffsetX
     */
    public double getOffsetX() {
        return mOffsetX;
    }

    /**
     * 手指Move的偏移量
     *
     * @return OffsetY
     */
    public double getOffsetY() {
        return mOffsetY;
    }

    /**
     * 获取距离手指按下点的distance
     *
     * @return DistanceToDownX
     */
    public double getDistanceToDownX() {
        return mDistanceToDownX;
    }

    /**
     * 获取距离手指按下点的distance
     *
     * @return DistanceToDownY
     */
    public double getDistanceToDownY() {
        return mDistanceToDownY;
    }

    /**
     * 联动容器{@link }是否处于起始位置
     *
     * @return isInStartPos
     */
    public boolean isInStartPos() {
        return mCurrentPos == mStartPos;
    }

    /**
     * 联动容器{@link }是否处于结束位置
     *
     * @return isInEndPos
     */
    public boolean isInEndPos() {
        return mCurrentPos == mEndPos;
    }

    /**
     * 联动容器{@link }已经离开StartPosition
     *
     * @return hasLeftStartPos
     */
    public boolean hasLeftStartPos() {
        return mCurrentPos > mStartPos;
    }

    /**
     * 联动容器{@link }刚刚离开StartPosition
     *
     * @return hasJustLeftStartPos
     */
    public boolean hasJustLeftStartPos() {
        return mLastPos == mStartPos && hasLeftStartPos();
    }

    /**
     * 联动容器{@link }刚刚回到StartPosition
     *
     * @return hasJustBackStartPos
     */
    public boolean hasJustBackStartPos() {
        return mLastPos != mStartPos && isInStartPos();
    }

    /**
     * 联动容器{@link }离开EndPosition位置
     *
     * @return hasLeftEndPos
     */
    public boolean hasLeftEndPos() {
        return mCurrentPos < mEndPos;
    }

    /**
     * 联动容器{@link }的位置刚刚离开终点位置
     *
     * @return hasJustLeftEndPos
     */
    public boolean hasJustLeftEndPos() {
        return mLastPos == mEndPos && hasLeftEndPos();
    }

    /**
     * 当前位置刚刚到达终点位置
     *
     * @return hasJustBackEndPos
     */
    public boolean hasJustBackEndPos() {
        return mLastPos != mEndPos && isInEndPos();
    }

    /**
     * position 边界检查，保证容器位置的可靠性。
     *
     * @param to to
     * @return checkPosBoundary
     */
    public int checkPosBoundary(int to) {
        to = Math.max(to, mStartPos);
        to = Math.min(to, mEndPos);

        return to;
    }

    /**
     * setCurrentPos
     *
     * @param currentPos currentPos
     */
    public void setCurrentPos(int currentPos) {
        mLastPos = mCurrentPos;
        mCurrentPos = currentPos;
    }

    /**
     * getCurrentPos
     *
     * @return CurrentPos
     */
    public int getCurrentPos() {
        return mCurrentPos;
    }

    /**
     * getLastPos
     *
     * @return LastPos
     */
    public int getLastPos() {
        return mLastPos;
    }

    /**
     * willOverStartPos
     *
     * @return willOverStartPos
     */
    public boolean willOverStartPos() {
        int to = (int) (mCurrentPos - mOffsetY);
        return to < mStartPos;
    }

    /**
     * willOverEndPos
     *
     * @return willOverEndPos
     */
    public boolean willOverEndPos() {
        int to = (int) (mCurrentPos - mOffsetY);
        return to > mEndPos;
    }

    /**
     * getStartPos
     *
     * @return StartPos
     */
    public int getStartPos() {
        return mStartPos;
    }

    /**
     * 获取联动容器{@link }的终点位置.
     *
     * @return EndPos
     */
    public int getEndPos() {
        return mEndPos;
    }

    /**
     * 获取联动容器{@link }当前位置相对于mStartPos的距离。
     *
     * @return PosDistanceFromStart
     */
    public int getPosDistanceFromStart() {
        return mCurrentPos - mStartPos;
    }

    /**
     * 获取联动容器{@link }位置的偏移量，相对于上次移动的位置：mLastPos
     *
     * @return PosOffset
     */
    public int getPosOffset() {
        return mCurrentPos - mLastPos;
    }


    /**
     * 记录横竖屏切换时当前Position的比例值。用于横竖屏切换后位置信息的恢复。
     */
    public void savePosOnConfigurationChanged() {
        mSaveCurrentPosRatio =
                (mCurrentPos - mStartPos) * 1.0f / (mEndPos - mStartPos);
        // 保留一位小数
        mSaveCurrentPosRatio = Math.round(mSaveCurrentPosRatio * 10) * 1.0f / 10;
        if (DEBUG) {
            LogUtil.loge("savePosOnConfigurationChanged, mSaveCurrentPosRation: " + mSaveCurrentPosRatio);
        }

    }

    /**
     * 保存position
     */
    private void restorePosIfNeeded() {
        if (mConfigurationHasChanged) {
            mCurrentPos =
                    (int) (mStartPos + ((mEndPos - mStartPos) * mSaveCurrentPosRatio));
            if (DEBUG) {
                LogUtil.loge("Need restore current pos, mCurrentPos: " + mCurrentPos);
            }
        }
    }


    @Override
    public String toString() {
        return "mCurrentPos: " + mCurrentPos
                + ", mLastPos: " + mLastPos
                + ", mPressedPos: " + mPressedPos
                + ", isInStartPos: " + this.isInStartPos()
                + ", isInEndPos: " + this.isInEndPos();
    }

}
